/* $Id: graphicalinput.jquery.js 28 2009-10-22 19:56:28Z geraldb $

Unobtrusive Accessible jQuery Graphical Form Inputs.

Overview:
	jQuery.fn.prettify()
	Wraps inputs with a span to be styled to act like a radio button/checkbox

Parameters:
	prepend: (String) Prepend wrapping span classes with this
		Default: 'prettify'

Usage:
	$('input').prettify()

Authors:
	gburns

TODO:
	Document
*/

(function($) {
$.fn.prettify = function(options) {
	var settings = $.extend({
		prepend: 'prettify_',
		type: 'default'
	}, options || {});

	return this.each(function() {
		if ( this.type == 'radio' || this.type == 'checkbox' ) {
			$.prettify.radioCheck(this, settings);
		} else if ( this.type == 'select-one' && settings.type == 'slider' ) {
			$.prettify.slider(this, settings);
		} else if ( this.type == 'submit' ) {
			$.prettify.button(this, settings);
		} else if ( this.type == 'text' || this.type == 'password' ) {
			$.prettify.text(this, settings);
		} else if ( this.type == 'textarea' ) {
			$.prettify.textarea(this, settings);
		}
	});
};

$.prettify = {
	textarea: function(element, settings) {
		var $this = $(element);

		var $wrap = $('<span>')
			.addClass(settings.prepend + 'textarea')
			.width($this.outerWidth())
			.addClass(($this.val() != '')?'has_text':'');

		if ( $this.is(':disabled') ) $wrap.addClass('disabled');

		var $start = $('<span>')
			.addClass(settings.prepend + 'textarea_start');

		var $track = $('<span>')
			.addClass(settings.prepend + 'textarea_track');

		var $end = $('<span>')
			.addClass(settings.prepend + 'textarea_end');

		var $label = $('<span>')
			.addClass(settings.prepend + 'textarea_label')
			.html($this.attr('title'));

		$wrap
			.append($start)
			.append($track)
			.append($end)
			.append($label);

		$this
			.after($wrap);

		$wrap
			.append($this);

		$this
			.bind('focus', function() {
				if ( !$this.is(':disabled') ) $wrap
					.addClass('focus');
			})
			.bind('blur', function() {
				$wrap
					.removeClass('focus');

				if ( $this.val() != '' ) {
					$wrap.addClass('has_text');
				} else {
					$wrap.removeClass('has_text');
				}
			});

		$label
			.bind('click', function() {
				element.focus();
			});

	},
	text: function(element, settings) {
		var $this = $(element);

		var $wrap = $('<span>')
			.addClass(settings.prepend + 'text')
			.width($this.outerWidth())
			.addClass(($this.val() != '')?'has_text':'');

		if ( $this.is(':disabled') ) $wrap.addClass('disabled');

		var $start = $('<span>')
			.addClass(settings.prepend + 'text_start');

		var $track = $('<span>')
			.addClass(settings.prepend + 'text_track');

		var $end = $('<span>')
			.addClass(settings.prepend + 'text_end');

		var $label = $('<span>')
			.addClass(settings.prepend + 'text_label')
			.html($this.attr('title'));

		$wrap
			.append($start)
			.append($track)
			.append($end)
			.append($label);

		$this
			.after($wrap);

		$wrap
			.append($this);

		$this
			.bind('focus', function() {
				if ( !$this.is(':disabled') ) $wrap
					.addClass('focus');
			})
			.bind('blur', function() {
				$wrap
					.removeClass('focus');

				if ( $this.val() != '' ) {
					$wrap.addClass('has_text');
				} else {
					$wrap.removeClass('has_text');
				}
			});

		$label
			.bind('click', function() {
				element.focus();
			});

	},
	button: function(element, settings) {
		var $this = $(element);

		var $wrap = $('<span>')
			.addClass(settings.prepend + 'button')
			.width($this.outerWidth());

		if ( $this.is(':disabled') ) $wrap.addClass('disabled');

		var $start = $('<span>')
			.addClass(settings.prepend + 'button_start');

		var $track = $('<span>')
			.addClass(settings.prepend + 'button_track');

		var $end = $('<span>')
			.addClass(settings.prepend + 'button_end');

		var $label = $('<span>')
			.addClass(settings.prepend + 'button_label')
			.html($this.val());

		$wrap
			.append($start)
			.append($track)
			.append($end)
			.append($label);

		$this
			.after($wrap);

		$wrap
			.append($this);

		$this
			.bind('focus', function() {
				if ( !$this.is(':disabled') ) $wrap
					.addClass('focus');
			})
			.bind('blur', function() {
				$wrap
					.removeClass('focus');
			})
			.bind('mousedown keydown', function(event) {
				if ( !$this.is(':disabled') ) $wrap.addClass('down');
			})
			.bind('mouseup keyup', function(event) {
				$wrap.removeClass('down');
			})
			.width($wrap.innerWidth() + 4);
		
	},
	slider: function(element, settings) {
		var $this = $(element);

		var $wrap = $('<span>')
			.addClass(settings.prepend + 'slider')
			.width($this.outerWidth());

		var $start = $('<span>')
			.addClass(settings.prepend + 'slider_start');

		var $track = $('<span>')
			.addClass(settings.prepend + 'slider_track');

		var $end = $('<span>')
			.addClass(settings.prepend + 'slider_end');

		var $handle = $('<span>')
			.addClass(settings.prepend + 'slider_handle');

		var return_false = function() { return false; }

		var $body = $(document.body);

		$wrap
			.append($start)
			.append($track)
			.append($end)
			.append($handle);

		$this
			.after($wrap);

		$wrap
			.append($this);

		var update_handle = function() {
			var count = $this[0].options.length;
			var index = $this[0].selectedIndex;
			var width = $wrap.outerWidth() - $handle.outerWidth();

			if ( index == 0 ) {
				$handle.css({left: 0});
			} else {
				var left = index/(count-1) * width;
				$handle.css({left: left});
			}

			$handle.attr({title: $this[0].options[index].text});
		};

		$this
			.bind('change', update_handle)
			.bind('keydown', function() {
				setTimeout(update_handle, 0);
			});

		update_handle();

		var mouse_start_x;
		var obj_start_x;
		var last_x;

		var drag = function(event) {
			var count = $this[0].options.length;
			var width = $wrap.outerWidth() - $handle.outerWidth();
			var left = obj_start_x - (mouse_start_x - event.pageX);
			var step = width/count;

			for ( var i=0; i<count; i++ ) {
				var min = step * (i);
				var max = step * (i+1);
				if ( i == 0 && left < max  ) {
					if (!$this[0].options[i].disabled) $this[0].selectedIndex = i;
					break;
				} else if ( i == count-1 && left >= width ) {
					if (!$this[0].options[i].disabled) $this[0].selectedIndex = i;
					break;
				} else if ( i != 0 && left >= min && left < max ) {
					if (!$this[0].options[i].disabled) $this[0].selectedIndex = i;
					break;
				}
			}

			update_handle();

			last_x = event.pageX;
		};

		var stop = function(event) {
			$body
				.unbind('mousemove', drag)
				.unbind('mouseup mouseleave', stop);

			$handle.removeClass('down');

			$body.css({MozUserSelect: ''});

			if ($.browser.msie) {
				$body
					.unbind('dragstart', return_false)
					.unbind('selectstart', return_false);
			}

			$this[0].focus();
		};

		$handle
			.bind('mousedown', function(event) {
				if ( $this.is(':disabled') ) return true;

				last_x = event.pageX;

				$handle.addClass('down');
				event.preventDefault();

				mouse_start_x = event.pageX;
				mouse_start_y = event.pageY;

				obj_start_x = parseInt($handle.css('left'));

				var old_moz_user_select = $body.css('MozUserSelect');
				$body.css({MozUserSelect: 'none'});

				$body
					.bind('mousemove', drag)
					.bind('mouseup mouseleave', stop);

				if ($.browser.msie) {
					$body
						.bind('dragstart', return_false)
						.bind('selectstart', return_false);
				}
			});



		$this
			.bind('focus', function() {
				if ( !$this.is(':disabled') ) $wrap
					.addClass('focus');
			})
			.bind('blur', function() {
				$wrap
					.removeClass('focus');
			});
	},
	radioCheck: function(element, settings) {
		var $this = $(element);

		if ( $this.attr('type') == 'radio' || $this.attr('type') == 'checkbox' ) {
			var $wrap = $('<span/>');

			$this
				.after($wrap);

			$wrap
				.append($this);

			if ( $this.is(':checked') ) $wrap.addClass('checked');

			if ( $this.is(':disabled') ) $wrap.addClass('disabled');

			$this
				.bind('focus', function() {
					if ( !$this.is(':disabled') ) $wrap
						.addClass('focus');
				})
				.bind('blur', function() {
					$wrap
						.removeClass('focus');
				});

			$wrap
				.bind('mouseover', function() {
					$wrap.addClass('over');
				})
				.bind('mouseout', function() {
					$wrap.removeClass('over');
				});

			if ( $this.attr('type') == 'radio' ) {
				$wrap
					.bind('click', function(event) {
						event.stopPropagation();
						$this.attr({checked: 'checked'});
						element.focus();

						setTimeout(function() {
							$('input:radio[name=' + $this.attr('name') + ']').each(function() {
								var $radio = $(this);
								if ( $radio.is(':checked') ) {
									$radio.parent().addClass('checked');
								} else {
									$radio.parent().removeClass('checked');
								}
							});
						}, 0);
					});

				$wrap
					.addClass(settings.prepend + 'radio');
			} else if ( $this.attr('type') == 'checkbox' ) {
				$wrap
					.bind('click', function(event) {
						event.stopPropagation();
						element.click();
						element.focus();
					});

				$this
					.bind('click', function(event) {
						event.stopPropagation();
						setTimeout(function() {
							if ( $this.is(':checked') ) {
								$wrap.addClass('checked');
							} else {
								$wrap.removeClass('checked');
							}
						}, 0);
					});

				$wrap
					.addClass(settings.prepend + 'checkbox');
			}
		}
	}
};
})(jQuery);
